home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
listings
/
v_10_11
/
crdtools.c
< prev
next >
Wrap
Text File
|
1992-06-16
|
18KB
|
533 lines
/* CRDTOOLS.C : Tools to exercise CORDIC calculations for sine/cosine.
* Make in Borland C++'s internal environment.
* (c) 1991 Michael Bertrand.
*/
#include <stdio.h> /* printf, scanf */
#include <math.h> /* sqrt, atan, sin, cos, fabs */
#include <conio.h> /* clrscr, gotoxy, getch, cputs, etc. */
#include <dos.h> /* struct time, gettime */
typedef unsigned int WORD;
typedef struct time TIME;
typedef struct
{
int x;
int y;
} POINT;
typedef struct
{
double u;
double v;
} DOUB_PT;
char Menu(void);
void SingleAngleDegree(void);
void SingleAngleCordic(void);
void ListSeries(void);
void CalcStatistics(void);
void TimeTest(void);
int HundSecs(TIME *tp, TIME *sp);
void CalcHexPtsCLib(POINT center, POINT vertex);
void CalcHexPtsCORDIC(POINT center, POINT vertex);
void SinCosSetup(void);
void SinCos(WORD theta, int *sin, int *cos);
#define TRUE 1
#define ESC 0x1B
/* Quadrants for angles. */
#define QUAD1 1
#define QUAD2 2
#define QUAD3 3
#define QUAD4 4
/* NBITS is number of bits used for CORDIC units. */
#define NBITS 14
/* NUM_PTS is number of vertices in polygon. */
#define NUM_PTS 6
/* Macros to convert angles to different units. */
#define DEG_TO_CORDIC(x) ((WORD) ((double)x/90.0*CordicBase + 0.5))
#define DEG_TO_RADIAN(x) (x/180.0*M_PI)
#define CORDIC_TO_RADIAN(x) ((double)x/CordicBase*M_PI/2)
/* NUM_TIMES is number of times to iterate for timing test. */
#define NUM_TIMES 1000
int ArcTan[NBITS]; /* angular constants : arctans */
int xInit; /* initial x projection */
WORD CordicBase; /* base for CORDIC units */
WORD HalfBase; /* CordicBase / 2 */
WORD Quad2Boundary; /* 2 * CordicBase */
WORD Quad3Boundary; /* 3 * CordicBase */
POINT HexPts[NUM_PTS+1]; /* to hold calculated polygon points */
void main(void)
{
SinCosSetup();
do
{
switch(Menu())
{
case '1' : case 'd': case 'D':
SingleAngleDegree();
break;
case '2' : case 'c': case 'C':
SingleAngleCordic();
break;
case '3' : case 'l': case 'L':
ListSeries();
break;
case '4' : case 's': case 'S':
CalcStatistics();
break;
case '5' : case 't': case 'T':
TimeTest();
break;
case '6' : case 'q': case 'Q':
clrscr();
return;
} /* switch */
} while (TRUE);
}
char Menu(void)
/*
USE : Display menu and get user choice.
RET : User choice.
*/
{
struct text_info ti; /* to get default text color */
gettextinfo(&ti);
clrscr();
textattr(LIGHTGRAY);
gotoxy(26, 1); cputs("╔═════ CORDIC Tests ═════╗");
gotoxy(26, 2); cputs("║ ║");
gotoxy(26, 3); cputs("║ 1) One Angle (Degree) ║");
gotoxy(26, 4); cputs("║ ║");
gotoxy(26, 5); cputs("║ 2) One Angle (CORDIC) ║");
gotoxy(26, 6); cputs("║ ║");
gotoxy(26, 7); cputs("║ 3) List Series ║");
gotoxy(26, 8); cputs("║ ║");
gotoxy(26, 9); cputs("║ 4) Statistics ║");
gotoxy(26,10); cputs("║ ║");
gotoxy(26,11); cputs("║ 5) Time Test ║");
gotoxy(26,12); cputs("║ ║");
gotoxy(26,13); cputs("║ 6) Quit ║");
gotoxy(26,14); cputs("║ ║");
gotoxy(26,15); cputs("║ Enter choice : ║");
gotoxy(26,16); cputs("╚════════════════════════╝");
textattr(RED);
gotoxy(43, 3); putch('D');
gotoxy(43, 5); putch('C');
gotoxy(32, 7); putch('L');
gotoxy(32, 9); putch('S');
gotoxy(32,11); putch('T');
gotoxy(32,13); putch('Q');
gotoxy(46, 15); /* put cursor inside box */
textattr(ti.attribute); /* restore default text color */
return(getch()); /* get char from user, return to main() */
}
void SingleAngleDegree(void)
/*
USE : Calculate sin/cos for single angle, in degrees.
NOTE: Also compares with actual values from C library functions.
*/
{
WORD theta; /* user-entered angle, in degrees */
int sinTheta; /* calculated sin in CORDIC units */
int cosTheta; /* calculated cos in CORDIC units */
double dSin; /* error in CORDIC calculation */
double dCos; /* error in CORDIC calculation */
gotoxy(25, 20);
printf("Enter angle, in degrees : ");
scanf("%u", &theta);
SinCos(DEG_TO_CORDIC(theta), &sinTheta, &cosTheta);
dSin = sin(DEG_TO_RADIAN(theta)) - (double) sinTheta / CordicBase;
dCos = cos(DEG_TO_RADIAN(theta)) - (double) cosTheta / CordicBase;
gotoxy(18, 22);
printf("%u deg : dSin = %8.5f dCos = %8.5f", theta, dSin, dCos);
gotoxy(24, 25);
printf("Press a key to continue ......");
getch();
}
void SingleAngleCordic(void)
/*
USE : Calculate sin/cos for single angle, in CORDIC units.
NOTE: Also compares with actual values from C library functions.
*/
{
WORD theta; /* user-entered angle, in CORDIC units */
int sinTheta; /* calculated sin in CORDIC units */
int cosTheta; /* calculated cos in CORDIC units */
double dSin; /* error in CORDIC calculation */
double dCos; /* error in CORDIC calculation */
gotoxy(22, 20);
printf("Enter angle, in CORDIC units : ");
scanf("%u", &theta);
SinCos(theta, &sinTheta, &cosTheta);
dSin = sin(CORDIC_TO_RADIAN(theta)) - (double) sinTheta / CordicBase;
dCos = cos(CORDIC_TO_RADIAN(theta)) - (double) cosTheta / CordicBase;
gotoxy(18, 22);
printf("%u CORDIC : dSin = %8.5f dCos = %8.5f", theta, dSin, dCos);
gotoxy(24, 25);
printf("Press a key to continue ......");
getch();
}
void ListSeries(void)
/*
USE : Calculate sin/cos for series of values (0 deg - 89 deg).
NOTE: Also compares with actual values from C library functions.
*/
{
WORD theta; /* increment from 0 to 89 (degrees) */
int sinTheta; /* calculated sin in CORDIC units */
int cosTheta; /* calculated cos in CORDIC units */
double dSin; /* error in CORDIC calculation */
double dCos; /* error in CORDIC calculation */
clrscr();
gotoxy(14,1); printf("╔═══════════════════════════════════════════════╗");
gotoxy(14,2); printf("║ Press <SPACE> to continue, <ESC> to quit. ║");
gotoxy(14,3); printf("╚═══════════════════════════════════════════════╝");
gotoxy(1, 5);
for (theta = 0; theta < 90; theta++)
{
SinCos(DEG_TO_CORDIC(theta), &sinTheta, &cosTheta);
dSin = sin(DEG_TO_RADIAN(theta)) - (double) sinTheta / CordicBase;
dCos = cos(DEG_TO_RADIAN(theta)) - (double) cosTheta / CordicBase;
printf("%3u deg : dSin = %8.5f dCos = %8.5f\n", theta, dSin, dCos);
if (getch() == ESC) return;
}
}
void CalcStatistics(void)
/*
USE : Calculate average error and worst error for all angles.
NOTE: Get worstError = 0.00064, avgError = 0.00011 for NBITS = 14
This is 13+ bits of precision for the average.
*/
{
WORD theta; /* to index thru all angles, in CORDIC units */
double thetaRad; /* theta in radians */
int sinTheta; /* calculated sin in CORDIC units */
int cosTheta; /* calculated cos in CORDIC units */
double dSin; /* error in CORDIC calculation (absVal) */
double dCos; /* error in CORDIC calculation (absVal) */
double accumError; /* accumulated error between CORDIC/actual sin/cos */
double avgError; /* average error per sin/cos */
double worstError; /* worst error for all sin/cos */
gotoxy(25,18); printf("╔══════════════════════════╗");
gotoxy(25,19); printf("║ Press <ESC> to quit. ║");
gotoxy(25,20); printf("╚══════════════════════════╝");
gotoxy(1, 21);
worstError = 0.0;
accumError = 0.0;
/* Update worstError and accumError as progress thru entire series. */
for (theta = 0; theta < CordicBase; theta++)
{
SinCos(theta, &sinTheta, &cosTheta);
thetaRad = CORDIC_TO_RADIAN(theta);
dSin = fabs(sin(thetaRad) - (double) sinTheta / CordicBase);